package com.yang.crawler.thread.manager;


import com.yang.crawler.dto.data.ThreadPoolMonitorDTO;
import com.yang.crawler.thread.ThreadPoolMonitorExecutor;
import com.yang.crawler.thread.factory.ThreadMonitorFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolMonitorManager {
    public static final int CORE_SIZE = Runtime.getRuntime().availableProcessors();

    public static final int MAX_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;

    public static final int WAIT_TIME = 60;

    public static final int MAX_CAPACITY = 500;

    public static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;

    public static final int SHUTDOWN_WAIT_TIME = 10;

    public static final TimeUnit SHUTDOWN_TIME_UNIT = TimeUnit.SECONDS;

    private static Map<String, ThreadPoolMonitorExecutor> threadPoolMonitorExecutorMap = new ConcurrentHashMap<>();


    public static ThreadPoolMonitorExecutor buildThreadPoolMonitorByTemplate(String poolName) {
        ThreadPoolMonitorExecutor threadPoolMonitorExecutor = new ThreadPoolMonitorExecutor(CORE_SIZE, MAX_SIZE,
                WAIT_TIME, TIME_UNIT, new LinkedBlockingQueue<>(MAX_CAPACITY),
                new ThreadMonitorFactory(poolName),
                new ThreadPoolExecutor.CallerRunsPolicy());
        threadPoolMonitorExecutorMap.put(poolName, threadPoolMonitorExecutor);
        return threadPoolMonitorExecutor;
    }

    public static Map<String, ThreadPoolMonitorExecutor> getThreadPoolMonitorExecutorMap() {
        return Collections.unmodifiableMap(threadPoolMonitorExecutorMap);
    }

    public static synchronized void shutdown() {
        for (ThreadPoolMonitorExecutor executor : threadPoolMonitorExecutorMap.values()) {
            try {
                if (!executor.isTerminated()) {
                    System.out.println("shutdown===");
                    executor.shutdown();

                    if (executor.awaitTermination(SHUTDOWN_WAIT_TIME, SHUTDOWN_TIME_UNIT)) {
                        System.out.println("shutdownNow===");
                        executor.shutdownNow();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static List<ThreadPoolMonitorDTO> getThreadPoolMonitorResults() {
        List<ThreadPoolMonitorDTO> threadPoolMonitorDTOList = new ArrayList<>();

        getThreadPoolMonitorExecutorMap().forEach((poolName, executor) -> {
            ThreadPoolMonitorDTO threadPoolMonitorDTO = new ThreadPoolMonitorDTO();
            threadPoolMonitorDTO.setPoolName(poolName);
            threadPoolMonitorDTO.setCoreSize(executor.getCorePoolSize());
            threadPoolMonitorDTO.setLargestSize(executor.getLargestPoolSize());
            threadPoolMonitorDTO.setMaxSize(executor.getMaximumPoolSize());
            threadPoolMonitorDTO.setThreadCount(executor.getPoolSize());
            threadPoolMonitorDTO.setMaxCostTime(executor.getMaxCostTime());
            threadPoolMonitorDTO.setAverageCostTime(executor.getAverageCostTime());
            threadPoolMonitorDTO.setMinCostTime(executor.getMinCostTime());
            threadPoolMonitorDTO.setActiveCount(executor.getActiveCount());
            threadPoolMonitorDTO.setCompletedTaskCount(executor.getCompletedTaskCount());
            threadPoolMonitorDTO.setQueueName(executor.getQueue().getClass().getName());
            threadPoolMonitorDTO.setRejectedName(executor.getRejectedExecutionHandler().getClass().getName());
            threadPoolMonitorDTO.setTotalTaskCount(executor.getTaskCount());

            threadPoolMonitorDTOList.add(threadPoolMonitorDTO);
        });
        return threadPoolMonitorDTOList;
    }
}